//
// Created by antler on 2018/12/10.
//

#include "tolua_helper.h"

void toluahelper_setfunc(lua_State *L, const luaL_Reg *l) {
    for (const luaL_Reg *lib = l; lib->func; lib++) {
        tolua_function(L, lib->name, lib->func);
    }
}

void *
toluahelper_tousertype(lua_State *L, int narg, const char *type, void *def, tolua_Error *err) {
    tolua_Error tolua_err = {narg, 0, type};
    if (tolua_isusertype(L, narg, type, LUA_TNIL, &tolua_err)) {
        return tolua_tousertype(L, narg, def);
    }
    if (err) {
        *err = tolua_err;
    }
    return def;
}

void toluahelper_json2table(lua_State *L, const std::string &json) {
    lua_getglobal(L, "cjson");
    lua_getfield(L, -1, "decode");
    lua_pushstring(L, json.c_str());
    lua_call(L, 1, 1);
    lua_replace(L, -2);
}

std::string toluahelper_table2json(lua_State *L, int idx) {
    std::string json;

    int type = lua_type(L, idx);
    if (type == LUA_TTABLE) {
        lua_getglobal(L, "cjson");
        lua_getfield(L, -1, "encode");
        lua_pushvalue(L, idx);
        lua_call(L, 1, 1);
        json = lua_tostring(L, -1);
        lua_pop(L, 2);
    }

    return json;
}

void toluahelper_keyvalue2table(lua_State *L, const std::string &key, bool value) {
    lua_newtable(L);
    lua_pushboolean(L, value ? 1 : 0);
    lua_setfield(L, -2, key.c_str());
}

void toluahelper_keyvalue2table(lua_State *L, const std::string &key, lua_Number value) {
    lua_newtable(L);
    lua_pushnumber(L, value);
    lua_setfield(L, -2, key.c_str());
}

void toluahelper_keyvalue2table(lua_State *L, const std::string &key, const std::string &value) {
    lua_newtable(L);
    lua_pushstring(L, value.c_str());
    lua_setfield(L, -2, key.c_str());
}

static int s_function_ref_id = 0;

void toluahelper_open(lua_State *L) {
    lua_pushstring(L, TOLUAHELPER_REFID_FUNCTION_MAPPING);
    lua_newtable(L);
    lua_rawset(L, LUA_REGISTRYINDEX);
}

int toluahelper_ref_function(lua_State *L, int lo) {
    if (!lua_isfunction(L, lo))
        return 0;

    s_function_ref_id++;

    lua_pushstring(L, TOLUAHELPER_REFID_FUNCTION_MAPPING);
    lua_rawget(L, LUA_REGISTRYINDEX);
    lua_pushinteger(L, s_function_ref_id); // Stack: fun, refid_fun_map, ref_id
    lua_pushvalue(L, lo);   // Stack: fun, refid_fun_map, ref_id, fun

    lua_rawset(L, -3); // Stack: fun, refid_fun_map[ref_id]=fun
    lua_pop(L, 1); // Stack: fun

    return s_function_ref_id;
}

void toluahelper_get_function_by_refid(lua_State *L, int refid) {
    lua_pushstring(L, TOLUAHELPER_REFID_FUNCTION_MAPPING);
    lua_rawget(L, LUA_REGISTRYINDEX); // Stack: refid_fun_map
    lua_pushinteger(L, refid); // Stack: refid_fun_map, refid
    lua_rawget(L, -2); // Stack: refid_fun_map, refid_fun_map[refid]
    lua_remove(L, -2); // Stack: refid_fun_map[refid]
}

void toluahelper_remove_function_by_refid(lua_State *L, int refid) {
    lua_pushstring(L, TOLUAHELPER_REFID_FUNCTION_MAPPING);
    lua_rawget(L, LUA_REGISTRYINDEX); // Stack: refid_fun_map
    lua_pushinteger(L, refid); // Stack: refid_fun_map, refid
    lua_pushnil(L); // Stack: refid_fun_map, refid, nil
    lua_rawset(L, -3); // Stack: refid_fun_map
    lua_pop(L, 1);
}
